#!/bin/sh
#
# AX
# Run X server with windows/desktop environment specified in the command line
#
# License: AGPL 3
#
# Version: 0.0.2
#
# Author: Viverna <viverna@inventati.org>

PREFIX="/usr/local"
ETCPREFIX="/usr/local"
VER="0.0.3"
COMMAND=$(basename "$0")
PARAMETERS=1
ERROR=""
ERRORLVL=""
SESSION="${HOME}/.xinitrc"
MLIST_G="${ETCPREFIX}/etc/${COMMAND}/client"
MLIST_L="${HOME}/.${COMMAND}/client"
SCRIPT_G="${ETCPREFIX}/etc/${COMMAND}/script.sh"
SCRIPT_L="${HOME}/.${COMMAND}/script.sh"
ARGS_G="${ETCPREFIX}/etc/${COMMAND}/args.sh"
ARGS_L="${HOME}/.${COMMAND}/args.sh"
POST_G="${ETCPREFIX}/etc/${COMMAND}/post.sh"
POST_L="${HOME}/.${COMMAND}/post.sh"
LANG_DIR="${ETCPREFIX}/etc/${COMMAND}/lang"


OPT_LOCALIZATION=0
OPT_LISTKNOWN=0
OPT_LISTAVAIL=0
OPT_VERSION=0
OPT_NOEXECX=0
OPT_HELP=0
OPT_CONFLICT=0

EXIT_SUCCESS=0
EXIT_ERROR_PARAM_MANY=1
EXIT_ERROR_OPT_UNKNOWN=2
EXIT_ERROR_OPT_CONFLICT=3
EXIT_ERROR_PATH_NOTFOUND=4
EXIT_ERROR_XINIT_RUN=5
EXIT_ERROR_ARGS_ERRORLVL=6


is_exist()
{
	ERRVAL=0
	if [ "$#" -eq "1" ]; then
		command -v "$1" > /dev/null 2>&1
		ERRVAL=$?
		if [ "${ERRVAL}" -eq "0" ]; then
			ERRVAL=1
		else
			ERRVAL=0
		fi
	fi
	return ${ERRVAL}
}

is_printf()
{
	ERRVAL=0
	if [ "$#" -eq "3" ]; then
		is_exist "$2"
		ERRVAL=$?
		if [ "$1" != "0" ] || [ "${ERRVAL}" -ne "0" ]; then
			printf "%s\n" "$3"
		fi
	fi
	return
}

printfde()
{
	if [ "$#" -eq "1" ]; then
		if [ -f "${MLIST_L}" ]; then
			while read -r KEY VALUE ARGS
			do
				is_printf "$1" "${VALUE}" "${KEY}"
			done < "${MLIST_L}"
		fi
		if [ -f "${MLIST_G}" ]; then
			while read -r KEY VALUE ARGS
			do
				is_printf "$1" "${VALUE}" "${KEY}"
			done < "${MLIST_G}"
		fi
	fi
}


search_desktop()
{
	if [ "$#" -eq "1" ]; then
		PATH_DESKTOP_FILE="/usr/share/xsessions/"
		SEARCH=$1
		
		for i in $(find ${PATH_DESKTOP_FILE} -name '*.desktop')
		do
			awk -F'=' -v section="[Desktop Entry]" -v k="Name" -v v="Exec" '
			$0==section{ flag=1; next }
			/^\[/{ flag=0; next } 
			flag && $1==k { name=$2; next } 
			flag && $1==v { exec=$2; next }
			END { printf name "=" exec }
			' $i | awk -F'=' -v z="${SEARCH}" '$1==z { printf $2 }'
		done
	fi
}


L=$(printf "%s" "${LANG}"|sed 's/\..\+//g')
if [ -x "${LANG_DIR}"/"${L}"/"${COMMAND}" ]; then
	. "${LANG_DIR}"/"${L}"/"${COMMAND}"
else
	AX_HELP=$(cat <<-ENDHELP
		Syntax: ${COMMAND} [-x] [windows/desktop manager]
		Syntax: ${COMMAND} -L
		Syntax: ${COMMAND} -l
		Syntax: ${COMMAND} -p
		Syntax: ${COMMAND} -V
		Syntax: ${COMMAND} -h
		
		[windows/desktop manager]: windows/desktop manager to run:
		[-L]: indicate the localization file
		[-l]: list windows/desktop manager known
		[-p]: list windows/desktop manager available
		[-x]: no execute xinit, create only a session file
		[-V]: print version and exit
		[-h]: print this and exit
		${COMMAND} to default run last windows/desktop manager used, if exist the file .xinitrc or run default windows/desktop
		
		Return a errorlevel:
		
		- 0 if success
		- different to 0 if error
	ENDHELP
	)

	AX_ERROR_PARAM_MANY="Too many parameters"
	AX_ERROR_OPT_UNKNOWN="Option not recognized"
	AX_ERROR_OPT_CONFLICT="Options incompatible with each other"
	AX_ERROR_PATH_NOTFOUND="Path windows/desktop manager not found"
	AX_ERROR_XINIT_RUN="Xinit is already running"

	AX_COMMENT_FILE_GLOBAL="#Global configuration files"
	AX_COMMENT_FILE_LOCAL="#Local configuration files"
	AX_COMMENT_RUN="#Run"
fi

# Parse command line with getopts
while getopts :LlpVxh f
	do
	case $f in
	L)
		OPT_LOCALIZATION=1
		OPT_CONFLICT=$((OPT_CONFLICT=${OPT_CONFLICT}+1))
		;;
	l)
		OPT_LISTKNOWN=1
		OPT_CONFLICT=$((OPT_CONFLICT=${OPT_CONFLICT}+1))
		;;
	p)
		OPT_LISTAVAIL=1
		OPT_CONFLICT=$((OPT_CONFLICT=${OPT_CONFLICT}+1))
		;;
	V)
		OPT_VERSION=1
		OPT_CONFLICT=$((OPT_CONFLICT=${OPT_CONFLICT}+1))
		;;
	x)
		OPT_NOEXECX=1
		;;
	h)
		OPT_HELP=1
		OPT_CONFLICT=$((OPT_CONFLICT=${OPT_CONFLICT}+1))
		;;
	# : invalid parameter
	# ? invalid option
	\?)
		printf "%s\n" "${COMMAND}: ${AX_ERROR_OPT_UNKNOWN}:'${OPTARG}'" >&2
		exit ${EXIT_ERROR_OPT_UNKNOWN}
		;;
	esac
done
shift $(expr ${OPTIND} - 1)

DM=$1
DM_PATH=""
if [ ${OPT_CONFLICT} -gt 1 ]; then
	ERROR="${COMMAND}: ${AX_ERROR_OPT_CONFLICT}"
	ERRORLVL=${EXIT_ERROR_OPT_CONFLICT}
elif [ ${OPT_CONFLICT} -eq 1 -a -n "${DM}" ]; then
	ERROR="${COMMAND}: ${AX_ERROR_OPT_CONFLICT}"
	ERRORLVL=${EXIT_ERROR_OPT_CONFLICT}
elif [ $# -gt ${PARAMETERS} ]; then
	ERROR="${COMMAND}: ${AX_ERROR_PARAM_MANY}"
	ERRORLVL=${EXIT_ERROR_PARAM_MANY}
fi


if [ -z "${ERROR}" ]; then
	if [ ${OPT_LOCALIZATION} -ne 0 ]; then
		if [ -x ${LANG_DIR}/${L}/${COMMAND} ]; then
			printf "%s\n" ${LANG_DIR}/${L}/${COMMAND}
		fi
		exit ${EXIT_SUCCESS}
	fi
	if [ $OPT_LISTKNOWN -ne 0 ]; then
		printfde 1
		exit ${EXIT_SUCCESS}
	fi
	if [ $OPT_LISTAVAIL -ne 0 ]; then
		printfde 0
		exit ${EXIT_SUCCESS}
	fi
	if [ $OPT_VERSION -ne 0 ]; then
		printf "%s\n" "${COMMAND}: $VER"
		exit ${EXIT_SUCCESS}
	fi
	if [ $OPT_HELP -ne 0 ]; then
		printf "%s\n" "$AX_HELP"
		exit ${EXIT_SUCCESS}
	fi

	if [ -n "${DM}" ]; then
		DM_NAME=""
		ARGS=""
		if [ -f ${MLIST_L} ]; then
			while read KEY VALUE ARGS
			do
				if [ "${DM}" = "${KEY}" ]; then
					DM_NAME=${VALUE}
					break
				fi
			done < ${MLIST_L}
		fi
		if [ -z ${DM_NAME} ]; then
			if [ -f ${MLIST_G} ]; then
				while read KEY VALUE ARGS
				do
					if [ "${DM}" = "${KEY}" ]; then
						DM_NAME=${VALUE}
						break
					fi
				done < ${MLIST_G}
			fi
		fi
		DM_PATH=""
		if [ -z ${DM_NAME} ]; then
			DM_PATH=$( search_desktop ${DM} )
		fi
		if [ -z "${DM_PATH}" ]; then
			if [ -z ${DM_NAME} ]; then
				DM_NAME=${DM}
			fi
			DM_PATH=$(command -v ${DM_NAME})
			if [ -z ${DM_PATH} ]; then
				ERROR="${COMMAND}: ${AX_ERROR_PATH_NOTFOUND}"
			fi
		fi
	fi
fi



# If windows/desktop manager has been found, create a session file
if [ -z "${ERROR}" -a -n "${DM_PATH}" ]; then
	printf "#!/bin/sh\n" > ${SESSION}
	if [ -f ${SCRIPT_G} ]; then
		printf "${AX_COMMENT_FILE_GLOBAL}\nif [ -f ${SCRIPT_G} ]; then\n\t${SCRIPT_G} ${DM}\nfi\n" >> ${SESSION}
	fi
	if [ -f ${SCRIPT_L} ]; then
		printf "${AX_COMMENT_FILE_LOCAL}\nif [ -f ${SCRIPT_L} ]; then\n\t${SCRIPT_L} ${DM}\nfi\n" >> ${SESSION}
	fi
	printf "${AX_COMMENT_RUN} ${DM}\nexec ${DM_PATH} ${ARGS}\n">>${SESSION}
fi

# If there is an error exit, else the script run xinit with windows/desktop manager chosen
if [ -n "${ERROR}" ]; then
	printf "%s\n" "${ERROR}" >&2
	exit ${ERRORLVL}
elif [ ${OPT_NOEXECX} -ne 0 ]; then
	exit ${EXIT_SUCCESS}
else
	# If xinit is running don't start xinit and exit with error
	if ps aux | grep -ve grep | grep -ho xinit >/dev/null; then
		ERROR="${COMMAND}: ${AX_ERROR_XINIT_RUN}"
		printf "%s\n" "${ERROR}" >&2
		exit ${EXIT_ERROR_XINIT_RUN}
	fi

	if [ -f ${ARGS_L} ]; then
		ARGS=$(${ARGS_L})
		ERR=$?
	elif [ -f ${ARGS_G} ]; then
		ARGS=$(${ARGS_G})
		ERR=$?
	else
		ARGS=
		ERR=0
	fi
	
	if [ "${ERR}" -eq "0" ]; then
		xinit $ARGS
		ERR=$?
	else
		printf "%s\n" "${ERR}" >&2
		exit ${EXIT_ERROR_ARGS_ERRORLVL}
	fi
	
	if [ -f ${POST_L} ]; then
		${POST_L} ${ERR}
	elif [ -f ${POST_G} ]; then
		${POST_G} ${ERR}
	fi
fi

exit $?

